import { Button, DatePicker, message, Modal, Progress, Select, Spin } from 'antd'
import ItemScopePreview from '@/views/ShoppingCart/components/ItemScopePreview.tsx'
import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react'
import { localShoppingData, tempData } from '@/views/ShoppingCart/LocalShoppingData.ts'
import {
  bindSepcById,
  getAreaSpec,
  getCompanyList,
  getIndustrySpec,
  getParkSpec,
  getPolymerizeSpec,
  getTableTargetFields,
  getTaskLogs,
  getTimeSpec,
  postAggregationField,
  postAreaField,
  postIndustryField,
  postParkField,
  postTimeField,
  unbindSepcById
} from '@/api/shoppingCart.ts'
import ChooseField from '@/views/ShoppingCart/components/ChooseField.tsx'
import { TimeOptions } from '@/views/ShoppingCart/SubmitShoppingOrder.tsx'
import { commonSelectProps } from '@/views/ShoppingCart/commonProps.ts'
import { HsAdminTable } from '@hs-admin/base-components'
import { hsHandleTableDateTime, initPageType, usePageChange } from '@hs-admin/utils'

const taskStatus = {
  running: 1,
  finished: <span className="text-green">完成</span>,
  terminated: <span className="text-red">终止</span>
}

const { RangePicker } = DatePicker

const columns = [
  {
    title: '调度时间',
    key: 'created_at',
    dataIndex: 'created_at',
    type: 'datetime'
  },
  {
    title: '执行完成时间',
    key: 'updated_at',
    dataIndex: 'updated_at',
    type: 'datetime',
    render: (time: string, row: any) => (typeof taskStatus[row.task_status] === 'number' ? '--' : hsHandleTableDateTime(time))
  },
  {
    title: '执行结果',
    key: 'task_status',
    dataIndex: 'task_status',
    render: (status: string, row: any) =>
      typeof taskStatus[status] === 'number' ? (
        <Progress percent={Number((row.progress * 100).toFixed(2))} size="small" />
      ) : (
        taskStatus[status] ?? '--'
      )
  },
  {
    title: '更新数量',
    key: 'row_count',
    dataIndex: 'row_count'
  }
]

const initPage: initPageType = {
  current: 1,
  total: 0,
  pageSize: 10
}

const ItemModal = forwardRef(
  (
    {
      onOk,
      isLocal,
      cartItemInfo
    }: { onOk: (() => void) | (() => Promise<boolean>); isLocal: boolean; cartItemInfo?: { specifications: any[]; spec_vals: any[] } },
    ref
  ) => {
    const [open, setOpen] = useState(false)
    const [itemId, setItemId] = useState('')

    const [openTimes, setOpentimes] = useState(0)

    const [forShow, setForShow] = useState(false)

    const [showFields, setShowFields] = useState(true)

    const dataNotModified = useRef({})

    const [extraField, setExtraField] = useState({
      industry: '',
      area: '',
      park: '',
      company_list: '',
      polymerize: [],
      time: []
    })

    const timer = useRef<any>(null)

    const [countKey, setCountKey] = useState(0)

    const [loading, setLoading] = useState(false)

    const [isCreateNew, setIsCreateNew] = useState(false)

    const [fieldList, setFieldList] = useState<any[]>([])

    const [options, setOptions] = useState<
      Array<{
        label: string
        value: string
      }>
    >([])

    const [syncMode, setSyncMode] = useState('')
    const [interval, setInterval] = useState('')

    const [logData, setLogData] = useState([])

    const logQuery = useRef<{
      times: null | [string, string]
      status: null | string
    }>({
      times: null,
      status: null
    })

    const request = useCallback(
      async (page: number, pageSize: number) => {
        if (!itemId) throw 'no id'
        const res = await getTaskLogs(itemId, {
          page,
          page_size: pageSize,
          task_status: logQuery.current.status || undefined,
          created_at_after: logQuery.current.times?.[0] || undefined,
          created_at_before: logQuery.current.times?.[1] || undefined
        })
        setLogData(res.items)
        return res.total ?? 0
      },
      [itemId]
    )

    const { pagination, resetPageAndTriggerRequest, handleChange } = usePageChange(initPage, request)

    useEffect(() => {
      clearTimeout(timer.current)
      if (logData.some((it) => it.task_status === 'running')) {
        timer.current = setTimeout(() => {
          handleChange(pagination.current)
        }, 3000)
      }
    }, [handleChange, logData])

    const showModal = (
      id: string,
      field: {
        industry?: string
        area?: string
        park?: string
        company_list?: string
        polymerize: Array<{
          label: string
          id: string
        }>
        time: Array<{
          label: string
          id: string
        }>
      },
      isOrderItem?: boolean,
      orderId?: string,
      showOnly?: boolean
    ) => {
      setExtraField(field)
      setOpen(true)
      setOpentimes((prevState) => prevState + 1)
      setItemId(id)
      setIsCreateNew(isOrderItem ?? false)
      setShowFields(true)

      if (!isOrderItem) {
        setOptions([])
        setFieldList([])
        setSyncMode('')
        setInterval('')
        setForShow(false)
      }

      if (isLocal) {
        const data = localShoppingData(id)
        tempData(data, true)
        dataNotModified.current = {
          industry: JSON.stringify(data?.['mapList'] ?? ''),
          area: JSON.stringify(data?.['areaList'] ?? ''),
          park: JSON.stringify(data?.['parkList'] ?? ''),
          time: JSON.stringify(data?.['time'] ?? ''),
          polymerize: JSON.stringify(data?.['polymerizeList'] ?? '')
        }

        if (isOrderItem) {
          if (showOnly) {
            setForShow(true)
            setShowFields(false)
          } else {
            setForShow(false)
          }
          setFieldList(data?.['fieldList'] ?? [])
          setSyncMode(data?.['sync_mode'] ?? '')
          setInterval(data?.['interval'] ?? '')
          const dst_tb_name = data?.['dst_tb_name']
          if (dst_tb_name && !showOnly) {
            getTableTargetFields(orderId, dst_tb_name).then((res) => {
              setOptions(
                (res ?? []).map((it) => ({
                  label: (
                    <div className="flex gap-2">
                      {it[0]}
                      <span className="text-sm text-gray">{it[1] && `(${it[1]})`}</span>
                    </div>
                  ),
                  value: it[0]
                }))
              )
            })
          }
        }
      }

      setCountKey((prevState) => prevState + 1)
    }

    useEffect(() => {
      if (itemId && forShow && open) {
        logQuery.current = {
          status: null,
          times: null
        }
        resetPageAndTriggerRequest()
      }
    }, [forShow, itemId, open, resetPageAndTriggerRequest])

    useEffect(() => {
      if (cartItemInfo) {
        let arr: any[] = []
        Object.keys(extraField).forEach((key) => {
          switch (key) {
            case 'industry':
              {
                const item = cartItemInfo.spec_vals.find((it) => it.type === 'industry')
                if (item) {
                  arr.push({
                    id: 'mapList',
                    req: getIndustrySpec(item.id).then((res) => {
                      tempData({
                        mapList: res.id_names.map((it) => ({
                          name: it.name,
                          id: Number(it.id)
                        }))
                      })
                    })
                  })
                }
              }
              break
            case 'area':
              {
                const item = cartItemInfo.spec_vals.find((it) => it.type === 'area')
                if (item) {
                  arr.push({
                    id: 'areaList',
                    req: getAreaSpec(item.id).then((res) => {
                      tempData({
                        areaList: res.vals
                      })
                    })
                  })
                }
              }
              break
            case 'park':
              {
                const item = cartItemInfo.spec_vals.find((it) => it.type === 'park')
                if (item) {
                  arr.push({
                    id: 'parkList',
                    req: getParkSpec(item.id).then((res) => {
                      tempData({
                        parkList: res.id_names.map((it) => ({
                          label: it.name,
                          value: it.id
                        }))
                      })
                    })
                  })
                }
              }
              break
            case 'company_list':
              {
                const item = cartItemInfo.spec_vals.find((it) => it.type === 'company_list')
                if (item) {
                  arr.push({
                    id: 'companyInfo',
                    req: async () => {
                      const res = await getCompanyList(item.id)
                      tempData({
                        companyInfo: {
                          id: item.id,
                          count: res.total
                        }
                      })
                    }
                  })
                }
              }
              break
            case 'polymerize':
              {
                const items = cartItemInfo.spec_vals.filter((it) => it.type === 'polymerize')
                if (items) {
                  arr = arr.concat(
                    items.map((it) => ({
                      parent: 'polymerize',
                      id: it.specification_id,
                      req: getPolymerizeSpec(it.id).then((res) => {
                        const data = tempData('polymerizeList') ?? {}
                        tempData({
                          polymerizeList: {
                            ...data,
                            [it.specification_id]: res.vals
                          }
                        })
                      })
                    }))
                  )
                }
              }
              break
            case 'time':
              {
                const items = cartItemInfo.spec_vals.filter((it) => it.type === 'time')
                if (items) {
                  arr = arr.concat(
                    items.map((it) => ({
                      parent: 'time',
                      id: it.specification_id,
                      req: getTimeSpec(it.id).then((res) => {
                        const data = tempData('time') ?? {}
                        tempData({
                          time: {
                            ...data,
                            [it.specification_id]: {
                              time1: res.start_time,
                              time2: res.end_time
                            }
                          }
                        })
                      })
                    }))
                  )
                }
              }
              break
          }
        })
        setLoading(true)
        Promise.all(arr.map((it) => it.req)).then(() => {
          const data = tempData()
          dataNotModified.current = {
            industry: JSON.stringify(data?.['mapList'] ?? ''),
            area: JSON.stringify(data?.['areaList'] ?? ''),
            park: JSON.stringify(data?.['parkList'] ?? ''),
            time: JSON.stringify(data?.['time'] ?? ''),
            polymerize: JSON.stringify(data?.['polymerizeList'] ?? '')
          }

          setCountKey((prevState) => prevState + 1)
          setLoading(false)
        })
      }
    }, [cartItemInfo, extraField])

    const handleOk = async () => {
      setLoading(true)

      const industry = tempData('mapList')

      if (industry?.length && dataNotModified.current.industry !== JSON.stringify(industry)) {
        const data = {
          id_names: industry.map((item: { name: string; id: number }) => ({
            name: item.name,
            id: String(item.id)
          }))
        }
        const res = await postIndustryField(data)
        tempData({ industryID: res.id })

        if (!isLocal) {
          const oldId = cartItemInfo?.spec_vals?.find((it) => it.type === 'industry')?.id
          if (oldId) {
            await unbindSepcById(itemId, oldId)
          }
          await bindSepcById(itemId, res.id)
        }
      } else {
        if (!industry?.length) {
          tempData({ industryID: null })
          if (!isLocal) {
            const oldId = cartItemInfo?.spec_vals?.find((it) => it.type === 'industry')?.id
            if (oldId) {
              await unbindSepcById(itemId, oldId)
            }
          }
        }
      }
      const area = tempData('areaList')
      if (area?.length && dataNotModified.current.area !== JSON.stringify(area)) {
        const data = { vals: area }
        const res = await postAreaField(data)
        tempData({ areaID: res.id })
        if (!isLocal) {
          const oldId = cartItemInfo?.spec_vals?.find((it) => it.type === 'area')?.id
          if (oldId) {
            await unbindSepcById(itemId, oldId)
          }
          await bindSepcById(itemId, res.id)
        }
      } else {
        if (!area?.length) {
          tempData({ areaID: null })
          if (!isLocal) {
            const oldId = cartItemInfo?.spec_vals?.find((it) => it.type === 'area')?.id
            if (oldId) {
              await unbindSepcById(itemId, oldId)
            }
          }
        }
      }
      const park = tempData('parkList')
      if (park?.length && dataNotModified.current.park !== JSON.stringify(park)) {
        const data = {
          id_names: park.map((item: { label: string; value: string }) => ({
            name: item.label,
            id: item.value
          }))
        }

        const res = await postParkField(data)
        tempData({ parkID: res.id })
        if (!isLocal) {
          const oldId = cartItemInfo?.spec_vals?.find((it) => it.type === 'park')?.id
          if (oldId) {
            await unbindSepcById(itemId, oldId)
          }
          await bindSepcById(itemId, res.id)
        }
      } else {
        if (!park?.length) {
          tempData({ parkID: null })

          if (!isLocal) {
            const oldId = cartItemInfo?.spec_vals?.find((it) => it.type === 'park')?.id
            if (oldId) {
              await unbindSepcById(itemId, oldId)
            }
          }
        }
      }
      const companyInfo = tempData('companyInfo')
      if (companyInfo?.id) {
        tempData({ companyID: companyInfo.id })
        if (!isLocal) {
          const oldId = cartItemInfo?.spec_vals?.find((it) => it.type === 'company_list')?.id
          if (oldId) {
            await unbindSepcById(itemId, oldId)
          }
          await bindSepcById(itemId, companyInfo.id)
        }
      } else {
        tempData({ companyID: null })
        if (!isLocal) {
          const oldId = cartItemInfo?.spec_vals?.find((it) => it.type === 'company_list')?.id
          if (oldId) {
            await unbindSepcById(itemId, oldId)
          }
        }
      }

      const time = tempData('time')
      if (time && Object.keys(time).length && dataNotModified.current.time !== JSON.stringify(time)) {
        const obj = {}
        for (let i = 0; i < extraField.time.length; i++) {
          if (time[extraField.time[i].id]?.time1) {
            const res = await postTimeField({
              specification_id: extraField.time[i].id,
              start_time: time[extraField.time[i].id]?.time1,
              end_time: time[extraField.time[i].id]?.time2 ?? ''
            })
            obj[extraField.time[i].id] = res.id

            if (!isLocal) {
              const oldId = cartItemInfo?.spec_vals?.find((it) => it.type === 'time' && it.specification_id === extraField.time[i].id)?.id
              if (oldId) {
                await unbindSepcById(itemId, oldId)
              }
              await bindSepcById(itemId, res.id)
            }
          } else {
            if (!isLocal) {
              const oldId = cartItemInfo?.spec_vals?.find((it) => it.type === 'time' && it.specification_id === extraField.time[i].id)?.id
              if (oldId) {
                await unbindSepcById(itemId, oldId)
              }
            }
          }
        }
        tempData({ timeID: obj })
      } else {
        if (!time || !Object.keys(time).length) {
          tempData({ timeID: null })
          if (!isLocal) {
            const oldItems = cartItemInfo?.spec_vals?.filter((it) => it.type === 'time')
            if (oldItems?.length) {
              for (const it of oldItems) {
                await unbindSepcById(itemId, it.id)
              }
            }
          }
        }
      }
      const polymerize = tempData('polymerizeList')
      if (polymerize && Object.keys(polymerize).length && dataNotModified.current.polymerize !== JSON.stringify(polymerize)) {
        const obj = {}
        for (let i = 0; i < extraField.polymerize.length; i++) {
          if (polymerize[extraField.polymerize[i].id]?.length) {
            const res = await postAggregationField({
              specification_id: extraField.polymerize[i].id,
              vals: polymerize[extraField.polymerize[i].id]
            })
            obj[extraField.polymerize[i].id] = res.id

            if (!isLocal) {
              const oldId = cartItemInfo?.spec_vals?.find((it) => it.type === 'polymerize' && it.specification_id === extraField.polymerize[i].id)?.id
              if (oldId) {
                await unbindSepcById(itemId, oldId)
              }
              await bindSepcById(itemId, res.id)
            }
          }
        }
        tempData({ polymerizeID: obj })
      } else {
        if (!polymerize || !Object.keys(polymerize).length) {
          tempData({ polymerizeID: null })

          if (!isLocal) {
            const oldItems = cartItemInfo?.spec_vals?.filter((it) => it.type === 'polymerize')
            if (oldItems?.length) {
              for (const it of oldItems) {
                await unbindSepcById(itemId, it.id)
              }
            }
          }
        }
      }

      if (isLocal) {
        if (fieldList.length) {
          const required_column_mappings = fieldList.filter((it) => it.is_required)
          if (required_column_mappings.length) {
            if (!required_column_mappings.every((it) => it.dst_col_name)) {
              message.error('“目标映射表名”或目标字段映射不完整')
              setLoading(false)
              return
            }
          }
        }

        tempData({
          fieldList,
          sync_mode: syncMode,
          interval
        })
        localShoppingData(itemId, tempData())
      }
      tempData({}, true)

      const done = await onOk()
      if (done === false) {
        setLoading(false)
      } else {
        setOpen(false)
        setLoading(false)
      }
    }

    const handleCancel = () => {
      setOpen(false)
      tempData({}, true)
    }

    useImperativeHandle(ref, () => ({
      showModal
    }))

    return (
      <Modal width="80vw" open={open} onOk={handleOk} onCancel={handleCancel}>
        <Spin spinning={loading}>
          <ItemScopePreview
            key={countKey}
            itemId={itemId}
            extraField={extraField}
            emptyText={isLocal ? '与整体范围一致' : '不限'}
            disabled={forShow}
          />
          {isCreateNew && (
            <>
              <div className="mb-4">
                同步方式：
                <Select
                  {...commonSelectProps}
                  disabled={forShow}
                  className="w-36"
                  value={syncMode}
                  options={[
                    {
                      label: '增量同步',
                      value: 'time_offset'
                    },
                    {
                      label: '全量同步',
                      value: 'whole'
                    }
                  ]}
                  onChange={(value) => {
                    setSyncMode(value)
                  }}
                />
              </div>
              <div>
                更新周期：
                <Select
                  {...commonSelectProps}
                  disabled={forShow}
                  className="w-36"
                  value={interval}
                  onChange={(value) => {
                    setInterval(value)
                  }}
                  options={TimeOptions}
                />
              </div>
              {forShow ? (
                <>
                  <h2 className="flex gap-4 py-2">
                    已选字段
                    <Button
                      type="link"
                      onClick={() => {
                        setShowFields((prevState) => !prevState)
                      }}>
                      {showFields ? '收起' : '展开'}
                    </Button>
                  </h2>
                  {showFields ? <ChooseField fieldList={fieldList} setFieldList={setFieldList} options={options} disabled={forShow} /> : null}
                </>
              ) : (
                <ChooseField fieldList={fieldList} setFieldList={setFieldList} options={options} disabled={forShow} />
              )}
              {forShow ? (
                <>
                  <h2 className="py-2">任务执行情况</h2>
                  <div key={openTimes} className="py-2 flex gap-4 items-center">
                    <div className="flex gap-2 items-center whitespace-nowrap">
                      调度时间:
                      <RangePicker
                        showTime
                        onChange={(_, dateString) => {
                          logQuery.current.times = dateString
                          resetPageAndTriggerRequest()
                        }}
                        className="mb-10px"
                        size="middle"></RangePicker>
                    </div>
                    <div className="flex gap-2 items-center whitespace-nowrap">
                      执行结果:
                      <Select
                        placeholder="请选择"
                        className="w-36"
                        options={[
                          {
                            label: '全部',
                            value: ''
                          },
                          {
                            label: '运行中',
                            value: 'running'
                          },
                          {
                            label: '完成',
                            value: 'finished'
                          },
                          {
                            label: '终止',
                            value: 'terminated'
                          }
                        ]}
                        onChange={(val) => {
                          logQuery.current.status = val
                          resetPageAndTriggerRequest()
                        }}
                      />
                    </div>
                  </div>
                  <HsAdminTable rowKey="id" id="deadModalTable" columns={columns} dataSource={logData} pagination={pagination} />
                </>
              ) : null}
            </>
          )}
        </Spin>
      </Modal>
    )
  }
)
export default ItemModal
